package cn.yx.common.security.webflux.filter;

import cn.hutool.core.util.StrUtil;
import cn.yx.common.core.exception.CommonException;
import cn.yx.common.redis.service.RedisService;
import cn.yx.common.security.constants.SecurityRedisCacheConstant;
import cn.yx.common.security.properties.SecurityProperties;
import cn.yx.common.security.webflux.constant.message.VerifyCodeAuthenticationFilterMessageKey;
import cn.yx.common.security.webflux.vo.in.VerifyCodeInVo;
import cn.yx.common.webflux.util.WebFluxUtil;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.Objects;

/**
 * <p>普通验证码认证过滤器</p>
 *
 * @author Wgssmart
 */
@Component
@Order(-25)
public class VerifyCodeAuthenticationFilter implements WebFilter {
    private final RedisService redisService;
    private final SecurityProperties securityProperties;

    public VerifyCodeAuthenticationFilter(RedisService redisService, SecurityProperties securityProperties) {
        this.redisService = redisService;
        this.securityProperties = securityProperties;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        if (StrUtil.equals(securityProperties.getVerifyCode().getLoginUrl(), request.getURI().getPath())) {
            HttpCookie httpCookie = getSessionCookie(request);
            checkCode(request, exchange.getResponse(), httpCookie.getValue());
        }
        return chain.filter(exchange);
    }

    /**
     * 获取会话cookie
     *
     * @param request
     * @return
     */
    private HttpCookie getSessionCookie(ServerHttpRequest request) {
        MultiValueMap<String, HttpCookie> cookieMap = request.getCookies();
        HttpCookie httpCookie = cookieMap.getFirst(securityProperties.getVerifyCode().getSessionName());
        if (Objects.isNull(httpCookie)) {
            // @SimplifiedChinese=不存在Session Cookie
            // @English=No Session Cookie
            throw new CommonException(VerifyCodeAuthenticationFilterMessageKey.NO_SESSION_COOKIE);
        }
        return httpCookie;
    }

    /**
     * 校验验证码
     *
     * @param request
     * @param response
     * @param sessionId
     */
    private void checkCode(ServerHttpRequest request, ServerHttpResponse response, String sessionId) {
        VerifyCodeInVo verifyCodeInVo = WebFluxUtil.getRequestData(request, VerifyCodeInVo.class);
        String codeInRedis = (String) redisService.get(SecurityRedisCacheConstant.CODE_LOGIN_PREFIX + sessionId);
        if (StrUtil.isEmpty(codeInRedis)) {
            // 验证码不存在
            WebFluxUtil.write(response, VerifyCodeAuthenticationFilterMessageKey.CODE_NOTE_EXIST);
            return;
        }
        if (!StrUtil.equals(verifyCodeInVo.getVerifyCode(), codeInRedis)) {
            // 验证码错误
            WebFluxUtil.write(response, VerifyCodeAuthenticationFilterMessageKey.CODE_ERROR);
        }
    }

}
